/*
 * @Description:
 * @Version: 1.0
 * @Autor: ycb
 * @Date: 2022-03-16 08:59:56
 * @LastEditors: ycb
 * @LastEditTime: 2022-04-08 12:19:38
 */
package server

import (
	"TITAN-STREAM-PROXY/public/hex"
	rabiitmq "TITAN-STREAM-PROXY/public/rabbitmq"
	"fmt"
	"log"
	"net"
	"net/http"
	"sync"
	"time"
)

func (hls_server *HLS) entry_hls(res http.ResponseWriter, req *http.Request) {
	var sucess bool = false
	_ = sucess
	var bytes []byte
	_ = bytes
	var stream_type StreamType
	_ = stream_type

	hls_server.lock.Lock()
	val, ok := hls_server.media_map[req.URL.Path]
	hls_server.lock.Unlock()
	if ok {
		sucess = true
		bytes = val.Contents
		stream_type = val.StreamType
	} else {
		sucess = false
		log.Printf("不存在路由%s", req.URL.Path)
	}

	if !sucess {
		res.WriteHeader(404)
		fmt.Fprintf(res, "未找到路由%s", req.URL.Path)
		return
	}
	switch stream_type {
	case M3U8:
		{
			res.Header().Add("Content-Type", "application/vnd.apple.mpegurl")
			res.Header().Add("Connection", "keep-alive")
			res.Header().Add("Access-Control-Allow-Origin", "*")
			res.Header().Add("Cache-control", "no-cache")

		}
		break
	case TS:
		{
			res.Header().Add("Content-Type", "video/mp2t")
			res.Header().Add("Connection", "keep-alive")
			res.Header().Add("Access-Control-Allow-Origin", "*")
			res.Header().Add("Cache-control", "no-cache")

		}
		break
	default:
		{
			fmt.Fprintf(res, "协议类型解析错了")
			return
		}
	}
	res.Write(bytes)
}

type StreamType int

const (
	// m3u8
	M3U8 StreamType = iota
	// ts
	TS
)

type Media struct {
	// 路由
	Path string
	// 内容
	Contents []byte
	// 创建时间
	CreateTime time.Time
	// 类型
	StreamType StreamType
}

// 解析序列化数据并将数据加入队列
func (hls_server *HLS) paserStream(stream_chan chan []byte) {
	for bytes := range stream_chan {
		// 取出数据进行解析
		//log.Printf("%s", bytes)
		var paser_index uint64 = 0
		_ = paser_index
		var m3u8_path_bytes []byte
		_ = m3u8_path_bytes
		var m3u8_bytes []byte
		_ = m3u8_bytes
		var ts_path_bytes []byte
		_ = ts_path_bytes
		var ts_bytes []byte
		_ = ts_bytes
		// 解析前8个字节
		for i := 0; i < 4; i++ {

			if (int)(paser_index+8) > len(bytes) {
				log.Printf("解析字节超长不合规")
				return
			}

			//先解析出长度
			length, sucess := hex.Hex2uint64(bytes[paser_index : paser_index+8])
			if !sucess {
				return
			}
			paser_index += 8
			if (int)(paser_index+length) > len(bytes) {
				log.Printf("解析字节超长不合规")
				return
			}
			bytes_ := bytes[paser_index : paser_index+length]
			paser_index += length

			switch i {
			// 如果是0解析的是m3u8路由
			case 0:
				{
					m3u8_path_bytes = bytes_
				}
				break
			// 如果是1解析的是m3u8
			case 1:
				{

					m3u8_bytes = bytes_
				}
				break
			// 如果是2解析的是ts路由
			case 2:
				{

					ts_path_bytes = bytes_
				}
				break
			case 3:
				{
					ts_bytes = bytes_
				}
				break
			}

		}

		hls_server.lock.Lock()
		hls_server.media_map[string(m3u8_path_bytes)] = Media{
			Path:       string(m3u8_path_bytes),
			Contents:   m3u8_bytes,
			CreateTime: time.Now(),
			StreamType: M3U8,
		}

		//log.Printf("收到m3u8: %s \n %s\n\n", string(m3u8_path_bytes), string(m3u8_bytes))

		hls_server.media_map[string(ts_path_bytes)] = Media{
			Path:       string(ts_path_bytes),
			Contents:   ts_bytes,
			CreateTime: time.Now(),
			StreamType: TS,
		}
		//log.Printf("收到路由%s 收到m3u8:%s", m3u8_path_bytes, m3u8_bytes)
		//log.Printf("收到ts路由%s ", ts_path_bytes)
		hls_server.lock.Unlock()

	}
}

var time_out int64 = 60

func (hls_server *HLS) clearMap() {
	for {
		time.Sleep(60 * time.Second)
		hls_server.lock.Lock()
		now_time_seconds := time.Now().Unix()
		for key, value := range hls_server.media_map {
			if now_time_seconds-value.CreateTime.Unix() >= time_out {
				log.Printf("删除过期的路由:%s  创建时间:%s 超时时间:%d",
					key, value.CreateTime.Format("2006-01-02 15:04:05"), time_out)
				delete(hls_server.media_map, key)
			}
		}
		hls_server.lock.Unlock()
	}
}

type HLS struct {
	RabbitConfig        RabbitMQConfig
	HLS_Port            string
	RabbitmqQueueConfig RabbitmqQueueConfig
	media_map           map[string]Media
	lock                sync.Mutex
}

func (hls_server *HLS) Start() {
	hls_server.media_map = make(map[string]Media)
	// 创建一个chan去接收从消息队列里拿出来的二进制数据
	stream := make(chan []byte)
	go hls_server.paserStream(stream)

	// 创建消息队列收数据
	client := &rabiitmq.RabbitMQPublishSubscribeClient{
		User: hls_server.RabbitConfig.User,
		Pwd:  hls_server.RabbitConfig.Pwd,
		IP:   hls_server.RabbitConfig.IP,
		Port: hls_server.RabbitConfig.Port,
	}

	go func() {
		Port := hls_server.HLS_Port
		//IsHttp := true

		hlsListen, err := net.Listen("tcp", Port)
		if err != nil {
			log.Fatal(err)
		}

		mux := http.NewServeMux()
		fmt.Println("HLS server listens at ", Port)

		mux.HandleFunc("/", hls_server.entry_hls)

		if err := http.Serve(hlsListen, mux); err != nil {
			return
		}
	}()

	// 开到携程里去
	go client.RecvMsg(hls_server.RabbitmqQueueConfig.Exchange,
		hls_server.RabbitmqQueueConfig.QueueName, stream)

	go hls_server.clearMap()

	// 阻塞
	select {}
}
